Hi, 大家好~~
昨天練習了一下SQL injection 發生的情境和語法,今天則是要研究Query Interface 章節中也令人相當興奮的方法——group
我們先來想像一下使用的情境:
首先,利用之前產生的todos 資料表:
以及其欄位資訊:
create_table "todos", force: :cascade do |t|
t.integer "userId"
t.text "title"
t.boolean "completed"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
end
來模擬今天的情境——利用completed
這欄來group
,看看總共有幾筆為true、幾筆為false:
irb(main):009:0> Todo.group(:completed)
Todo Load (3.1ms) SELECT "todos".* FROM "todos" GROUP BY "todos"."completed"
Traceback (most recent call last):
ActiveRecord::StatementInvalid (PG::GroupingError: ERROR: column "todos.id" must appear in the GROUP BY clause or be used in an aggregate function)
LINE 1: SELECT "todos".* FROM "todos" GROUP BY "todos"."completed"
^
不知道大家有沒有踩過這個坑?想說documents 上也是這麼用的呀:
但我們冷靜些,先來看看當我們這麼query 的時候,statement 和documents 上的有何不同?
SELECT "todos".* FROM "todos" GROUP BY "todos"."completed"
# vs.
SELECT "users".* FROM "users" GROUP BY name
# 似乎真的不同?
那我偷吃步跟Guide 這麼做:
sql = "SELECT \"todos\".* FROM \"todos\" GROUP BY \"completed\""
irb(main):030:0> Todo.find_by_sql(sql)
Todo Load (1.9ms) SELECT "todos".* FROM "todos" GROUP BY "completed"
Traceback (most recent call last):
1: from (irb):30
ActiveRecord::StatementInvalid (PG::GroupingError: ERROR: column "todos.id" must appear in the GROUP BY clause or be used in an aggregate function)
LINE 1: SELECT "todos".* FROM "todos" GROUP BY "completed"
^
等一下,這騙人的吧!why!!!雖然訊息有提示todos.id
也必須要在group 的query statement 內,但其實很不甘心的!為什麼Guide 裡User.group(:name)
可以用呢,怒!
但我們先委屈、傲嬌地跟著修改一下吧:
Todo.group([:id, :completed])
Todo.group(:id, :completed)
# 可無論怎麼嘗試
irb(main):043:0> Todo.group([:id, :completed]).to_sql
"SELECT \"todos\".* FROM \"todos\" GROUP BY \"todos\".\"id\", \"todos\".\"completed\""
irb(main):044:0> Todo.group(:id, :completed).to_sql
"SELECT \"todos\".* FROM \"todos\" GROUP BY \"todos\".\"id\", \"todos\".\"completed\""
# SQL 的statement 還是一樣的
重點是回傳的資料一點也不像有被group
或group_by
!
偷用圖形化工具查看呢?
怒欸!難道跟arguments 內的順序有關:
irb(main):047:0> Todo.group(:completed, :id).to_sql
"SELECT \"todos\".* FROM \"todos\" GROUP BY \"todos\".\"completed\", \"todos\".\"id\""
可還是得到了個令人無言又生氣的結果:
當我們參考documents 時:
好像煞有其事的樣子!?
但無論怎麼修改arguments 的順序,都還是得到了個不具可讀性的結果:
跟著做到這邊,其實真的很想哭,一方面覺得自己無知,一方面覺得到底在做啥!!
且跟著API dock 去看他User 的欄位資訊有何不同?
阿就真的沒有啊:
所以這頁group
解釋了什麼、或說明了什麼嗎?老實說我感覺不到啊啊啊啊!!!
雖然這句話倒是令人有點理解了什麼、可又不太能明白的感覺?
Returns an array with distinct records based on the group attribute:
翻譯蒟蒻:group
會回傳一個根據attribute 且獨特的資料array
但還是不能解釋為什麼有group 和沒group... 都是根據id grouping 而不是用completed?
難怪總是回傳了200 筆資料!?
但如果我們利用這概念這麼做:
irb(main):076:0> Todo.select(:completed).group(:completed)
Todo Load (1.3ms) SELECT "todos"."completed" FROM "todos" GROUP BY "todos"."completed"
[
[0] #<Todo:0x00007fc723f42eb8> {
"id" => nil,
"completed" => false
},
[1] #<Todo:0x00007fc723f42d28> {
"id" => nil,
"completed" => true
}
]
好像就能得到近似我們要的結果了?
而再加上count
:
irb(main):078:0> Todo.select(:completed).group(:completed).count
(0.7ms) SELECT COUNT("todos"."completed") AS count_completed, "todos"."completed" AS todos_completed FROM "todos" GROUP BY "todos"."completed"
{
false => 110,
true => 90
}
所以說..... 究竟是為什麼呢?不要這樣搞我啊~~
但總之今天的研究就先到這裡囉,被翻爛的書先去沉澱一下自己的心情......